#pragma once
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <unistd.h>
#include "Log.hpp"
#include "Err.hpp"

const int defaultfd = -1;

class Sock {
public:
    Sock() : sock_(defaultfd) {}
    void Socket() {
        sock_ = socket(AF_INET, SOCK_STREAM, 0);
        if (sock_ < 0) {
            Logger::getInstance().loggger()->fatal("socket error, code: %d, errstring: %s", errno, strerror(errno));
            exit(SOCKET_ERR);
        }
        // 设置地址是复用的
        int opt = 1;
        setsockopt(sock_, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt));
        int flags = fcntl(sock_, F_GETFL, 0);        //获取文件的flags值
        fcntl(sock_, F_SETFL, flags | O_NONBLOCK);   //设置成非阻塞模式
    }
    void Bind(const uint16_t &port) {
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port);
        local.sin_addr.s_addr = inet_addr(Config::GetInstance()->GetServerIp().c_str());

        if (bind(sock_, (struct sockaddr *)&local, sizeof(local)) < 0) {
            Logger::getInstance().loggger()->fatal("bind error, code: %d, errstring: %s", errno, strerror(errno));
            exit(BIND_ERR);
        }
    }
    void Listen() {
        if (listen(sock_, Config::GetInstance()->GetGblacklog()) < 0) {
            Logger::getInstance().loggger()->fatal("listen error, code: %d, errstring: %s", errno, strerror(errno));
            exit(LISTEN_ERR);
        }
    }
    int Accept(std::string *clientip, uint16_t *clientport) {
        struct sockaddr_in temp;
        socklen_t len = sizeof(temp);
        int sock = accept(sock_, (struct sockaddr *)&temp, &len);
        if (sock < 0)
            Logger::getInstance().loggger()->fatal("accept error, code: %d, errstring: %s", errno, strerror(errno));
        else {
            *clientip = inet_ntoa(temp.sin_addr);
            *clientport = ntohs(temp.sin_port);
        }
        return sock;
    }
    int Connect(const std::string &serverip, const uint16_t &serverport) {
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(serverport);
        server.sin_addr.s_addr = inet_addr(serverip.c_str());

        return connect(sock_, (struct sockaddr *)&server, sizeof(server));
    }
    int Fd() {
        return sock_;
    }
    void Close() {
        if (sock_ != defaultfd)
            close(sock_);
    }
    ~Sock() {}

private:
    int sock_;
};
